'use strict'

const _ = require('lodash')
const { TARGET } = require('../config')

const DOC = process.env.DOC

const errors = require('../i18n/error.js')

function writeDoc(ctx, title) {
    /**
     * Print test case title
     */
    console.log(`## ${title}\n`)
    console.log(`* Endpoint: \`${ctx.url.replace(/\/api\/v1/, '[API ROOT]')}\``)
    console.log(`* Method: \`${ctx.method}\``)
    console.log(`* Authentication: \`${ctx.get('token') ? '' : 'NOT '}REQUIRED\`\n`)

    /**
     * Print request url params object
     * @type {NULL}
     */
    const raw = _.pickBy(ctx.params, (val, key) => {
        return /^[a-zA-Z]/.test(key)
    })

    if (Object.keys(raw).length > 0) {
        console.log('URL Params')
        console.log('```')
        console.log(JSON.stringify(raw, null, 2))
        console.log('```\n')
    }

    /**
     * Print request query string object with pagination if exist
     * @type {NULL}
     */
    const query = _.extend({},
        ctx.query,
        ctx.pagination ?
        _.pick(ctx.pagination, ['limit', 'page']) : {}
    )

    if (Object.keys(query).length > 0) {
        console.log('Query')
        console.log('```')
        console.log(JSON.stringify(query, null, 2))
        console.log('```\n')
    }

    /**
     * Print request method and url
     * @return {NULL}
     */
    if (ctx.method !== 'GET') {
        if (Object.keys(ctx.request.body).length > 0) {
            console.log('JSON Body')
            console.log('```')
            console.log(JSON.stringify(ctx.request.body, null, 2))
            console.log('```\n')
        }
    }

    /**
     * Print response object
     * @return {NULL}
     */
    console.log('Returns')
    console.log('```')
    console.log(ctx.body)
    console.log('```\n\n\n')
}

async function prod(ctx, next) {
    const start = Date.now()

    try {
        await next()
    } catch (err) {
        console.error(JSON.stringify(err, null, 4))

        if (err.name === 'UnauthorizedError' && err.message === 'Unauthorized') {
            ctx.status = 401
            return ctx.set('WWW-Authenticate', 'Basic')
        }

        if (err.name === 'SyntaxError') {
            return ctx.err(422, 'UnprocessableEntity')
        }

        if (err.name === 'SequelizeUniqueConstraintError') {
            return ctx.err(400, 'ConditionalValidation')
        }

        const message = errors[err.message]
        if (!message) {
            // Print log
            const log = JSON.stringify({
                token: ctx.get('token'),
                ip: ctx.ip,
                UserAgent: ctx.get('User-Agent'),
                datetime: new Date(),
                method: ctx.method,
                path: ctx.path,
                params: ctx.params,
                query: ctx.query,
                body: ctx.request.body,
                stack: err.stack
            }, null, 4)

            console.log(log)
        }

        ctx.err(err.status, err.message, message)
    }

    // Logger
    const ms = Date.now() - start
    console.log(`${ctx.method} ${ctx.status} ${ctx.path} ${ctx.ip} ${ms}ms`)
}

async function test(ctx, next) {
    try {
        await next()

        if (DOC) {
            const title = ctx.get('X-Doc-Title')
            if (title) {
                writeDoc(ctx, title)
            }
        }
    } catch (err) {
        // Print error
        if (err.name === 'UnauthorizedError' && err.message === 'Unauthorized') {
            ctx.status = 401
            return ctx.set('WWW-Authenticate', 'Basic')
        }

        if (err.name === 'SyntaxError') {
            return ctx.err(422, 'UnprocessableEntity')
        }

        if (err.name === 'SequelizeUniqueConstraintError') {
            return ctx.err(400, 'ConditionalValidation')
        }

        if (!errors[err.message]) {
            console.error(err.message)
        }

        ctx.status = err.status || 500
        return ctx.body = err.message
    }
}

module.exports = TARGET === 'test' ? test : prod